package com.hwtx.form.def.meta;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.hwtx.form.MockRacServiceImpl;
import com.hwtx.form.domain.FormServiceImpl;
import com.hwtx.form.domain.def.meta.config.ApiSelectComponentConfig;
import com.hwtx.form.domain.def.meta.config.ChainSelectFormComponentConfig;
import com.hwtx.form.domain.def.meta.config.GroupChainSelectFormComponentConfig;
import com.hwtx.form.domain.def.meta.config.SelectComponentConfig;
import com.hwtx.form.domain.handle.ResourceFormHandle;
import com.hwtx.form.domain.handle.ResourceFormHandleAction;
import com.hwtx.form.domain.handle.core.DefaultFormDataHandle;
import com.hwtx.form.domain.handle.core.DefaultFormDataReadHandle;
import com.hwtx.form.domain.handle.core.DefaultFormDataWriteHandle;
import com.hwtx.form.domain.handle.core.DefaultFormDefHandle;
import com.hwtx.form.domain.listener.EventPublisher;
import com.hwtx.form.domain.listener.FormDataChangeInterceptor;
import com.hwtx.form.domain.meta.FunPermCache;
import com.hwtx.form.domain.service.*;
import com.hwtx.form.persistence.DataSourceRepo;
import com.hwtx.form.persistence.SysUserRepoImpl;
import com.hwtx.form.persistence.ds.DatasourceDao;
import com.zaxxer.hikari.HikariDataSource;
import io.geekidea.boot.config.properties.BootProperties;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.sql.DataSource;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Configuration
@MapperScan({"com.hwtx.form.persistence.mapper", "io.geekidea.boot.system.mapper"})
@ComponentScan(basePackages = {"com.hwtx.form.persistence"},
        excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
                classes = {DatasourceDao.class, DataSourceRepo.class, SysUserRepoImpl.class}))
public class MyBatisConfig {

    @Bean
    public BootProperties bootProperties() {
        BootProperties bootProperties = new BootProperties();
        BootProperties.FormConfig formConfig = new BootProperties.FormConfig();
        formConfig.setLoadFormByLocal(true);
        bootProperties.setDomain("http://localhost:8080");
        bootProperties.setForm(formConfig);
        return bootProperties;
    }

    @Bean
    public SpringUtil springUtil() {
        return new SpringUtil();
    }

    @Bean
    public ResourceFormHandle resourceFormHandle() {
        return new ResourceFormHandle();
    }

    @Bean
    public ResourceFormHandleAction resourceFormHandleAction() {
        return new ResourceFormHandleAction();
    }

    @Bean
    public RacService racService() {
        return new MockRacServiceImpl();
    }

    @Bean
    public EventPublisher eventPublisher() {
        return new EventPublisher();
    }

    @Bean
    public DefaultFormDefHandle defaultFormDefHandle() {
        return new DefaultFormDefHandle();
    }

    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        return new RequestMappingHandlerMapping();
    }

    @Bean
    public DataSource dataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); // MySQL driver
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_boot_plus?useSSL=false&serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    @Bean
    public DatasourceDao datasourceDao(JdbcTemplate jdbcTemplate) {
        return new DatasourceDao(jdbcTemplate);
    }

    @Bean
    public DataSourceRepo metadataRepo() {
        return new DataSourceRepo();
    }

    @Bean
    public SelectComponentConfig selectComponentConfig() {
        return new SelectComponentConfig();
    }

    @Bean
    public ChainSelectFormComponentConfig chainSelectFormComponentConfig() {
        return new ChainSelectFormComponentConfig();
    }

    @Bean
    public GroupChainSelectFormComponentConfig groupChainSelectFormComponentConfig() {
        return new GroupChainSelectFormComponentConfig();
    }

    @Bean
    public ApiSelectComponentConfig apiSelectComponentConfig() {
        return new ApiSelectComponentConfig();
    }

    @Bean
    public FunPermCache funPermCache() {
        return new FunPermCache();
    }

    @Bean
    ServerProperties serverProperties() {
        return new ServerProperties() {
            @Override
            public Servlet getServlet() {
                return new Servlet() {
                    @Override
                    public String getContextPath() {
                        return "/api";
                    }
                };
            }
        };
    }

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();

        // 默认配置（适用于所有缓存名称）
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .expireAfterWrite(5, TimeUnit.HOURS)  // 写入后10分钟过期
                .maximumSize(1000)                        // 最大缓存数量
                .recordStats());                         // 开启统计
//
//        // 可以为特定缓存名称设置不同的配置
//        cacheManager.registerCustomCache("userCache", Caffeine.newBuilder()
//                .expireAfterWrite(30, TimeUnit.MINUTES)
//                .maximumSize(1000)
//                .build());
        return cacheManager;
    }

    @Bean
    @Primary
    JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean
    public List<FormDataChangeInterceptor> interceptors() {
        return List.of();
    }

    @Bean
    public DefaultFormDataReadHandle defaultFormDataReadHandle() {
        return new DefaultFormDataReadHandle();
    }

    @Bean
    public DefaultFormDataWriteHandle defaultFormDataWriteHandle() {
        return new DefaultFormDataWriteHandle();
    }

    @Bean
    public TenantsService tenantsService() {
        return new TenantsService();
    }

    @Bean
    public CommonApiInvoker commonApiInvoker() {
        return new CommonApiInvoker();
    }

    @Bean
    public ResourceService resourceService() {
        return new ResourceServiceImpl();
    }

    @Bean
    public FormService formService() {
        return new FormServiceImpl();
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource, ApplicationContext applicationContext) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setConfiguration(new MybatisConfiguration());
        factoryBean.setMapperLocations(applicationContext.getResources("classpath*:mapper/**/*Mapper.xml"));
        return factoryBean.getObject();
    }

    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public DefaultFormDataHandle defaultFormDataHandle() {
        return new DefaultFormDataHandle();
    }
}